home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
scope
/
001-025
/
scopedisk14
/
cc
/
cc.c
next >
Wrap
Text File
|
1995-03-18
|
25KB
|
807 lines
/************************************************************************
* *
* Copyright (c) 1985, Fred Fish *
* All Rights Reserved *
* *
* This software and/or documentation is released into the *
* public domain for personal, non-commercial use only. *
* Limited rights to use, modify, and redistribute are hereby *
* granted for non-commercial purposes, provided that all *
* copyright notices remain intact and all changes are clearly *
* documented. The author makes no warranty of any kind with *
* respect to this product and explicitly disclaims any implied *
* warranties of merchantability or fitness for any particular *
* purpose. *
* *
************************************************************************
*/
/*
* cc -- C compiler front end for Amiga and Lattice C.
*
* Somewhat AMIGA/Lattice dependent, but can probably be adapted to
* other systems with a minimum of work. I have attempted to keep
* portability in mind as much as possible.
*
* Changes by mwm: (look for comments tagged mwm)
* 1) Change link lib for 3.03.
* 2) Fix abortion for 3.10, which does it better.
* 3) Comment on what all flags do.
* 4) Add rest of 4.3BSD flags (well, 4.3beta).
* 5) Move Amiga-specific flags to -A
* 6) Use INCLUDE: instead of searching for include directory.
* 7) Change ALINK to BLINK (as per 3.10)
* 8) Define LATTICE at compile time.
* 9) Add -A flags for SMALLCODE, SMALLDATA, and disabling stack
* checking
* 10) Implement the -g flag.
* 11) LIB: is now searched last for libraries, and
* 12) LC: is now searched last for commands.
* 13) Add code to handle objects landing in specific memory.
* 14) Add -. to turn off copyright messages.
* And now the changes for 4.0:
* 15) Change default quad device to QUAD:.
* 16) Turn off source in error messages
* 17) Turn off warnings about structures as function args
* 18) Turn on cheks for real prototypes.
* 19) Add -Ap to turn off prototype checking.
* 20) Add -Af to use motorola FFP instead of IEEE.
* 21) Add -As to get source listings out anyway.
* 22) Add prototypes and include string.h
*/
char _sccsid[] = "@(#)cc.c 1.8";
#include <stdio.h>
#include <string.h>
/*
* The following allow use on systems that don't have my macro based
* debugging package. The default, for now, is to assume it is not
* available.
*/
#ifdef DBUG
# include <local/dbug.h>
#else /* !DBUG */
# define DBUG_ENTER(a)
# define DBUG_RETURN(a) return(a)
# define DBUG_VOID_RETURN return
# define DBUG_2(a,b)
# define DBUG_3(a,b,c)
# define DBUG_4(a,b,c,d)
# define DBUG_5(a,b,c,d,e)
# define DBUG_PUSH(a)
#endif /* DBUG */
/*
* IMPLEMENTATION NOTES
*
* Some of the builtin (artificial) limits could be removed by
* using dynamically allocated data structures, such as keeping the
* operand list as a linked list with space for each link supplied
* by malloc. This would certainly increase the code space, while
* reducing the statically allocated data space. The net result
* would probably be a program requiring about the same amount of
* total memory for most day to day usages. When source is not
* available to the end user, maximum flexibility is a must and
* dynamic allocation is the only way to go. In this case however
* it is not clear that the added complexity is worth it, since
* source should be available for anyone wishing to expand the
* limits.
*
* One last note, if you are going to have builtin limits then
* check the @#$%&* things for overflow. Running off the end of
* an array with no indication that something is wrong, other
* than a crash, if definitely unfriendly!
*
*/
/*
* Manifest constants which can be tuned to fit requirements.
*/
#define CMDBUFFERSIZE (1024) /* Size of command buffer for CLI command */
#define MAXOPERANDS (64) /* Maximum number of operands on cmd line */
#define MAXDEFINES (32) /* Maximum number of -D<name> args */
#define MAXUNDEFINES (32) /* Maximum number of -U<name> args */
#define MAXINCDIRS (16) /* Maximum number of -I<filename> args */
#define MAXLIBS (16) /* Maximum number of -l<lib> args */
#define ARGSIZE (64) /* Size of temp args for cmd line */
/*
* Define QUADDEV to be the default place where you want the compiler
* intermediate files (quad files) to be created. As of 4.0, we follow
* Lattice in making this be the QUAD: assigned name. Most of the time,
* it'll work fine in ram:, but large compiles may want it on a disk.
* In either case, the default can be overridden with the -q option.
*/
#define QUADDEV "QUAD:" /* Keep intermediate files in assigned place */
/* #define QUADDEV "ram:" */ /* Keep intermediate files in ram: */
/* #define QUADDEV "" */ /* Keep intermediate files in current dir */
/*
* Manifest constants which are generally the same on all systems.
*/
#define EOS '\000' /* End of string character */
/*
* Command line arguments that represent files to be compiled, assembled,
* or linked, are kept track of via an "Operand" array. If, for example,
* the file name is "df0:mydir/junk.c", then the Rootname is
* "df0:mydir/junk", the Basename is "junk", and the Suffix is "c".
* String suffixes are used, rather than single character suffixes, to
* allow use of names with multicharacter suffixes.
*/
struct Operand { /* Info about each operand (non option) */
char *Rootname; /* Name minus any suffix */
char *Basename; /* Name minus any prefix or suffix */
char *Suffix; /* Suffix of operand */
};
static struct Operand Operands[MAXOPERANDS]; /* Table of operands */
static int NOperands = 0; /* Number of operands found */
static char *Defines[MAXDEFINES]; /* Table of defines */
static int NDefines = 0; /* Number of defines */
static char *UnDefines[MAXUNDEFINES]; /* Table of undefines */
static int NUnDefines = 0; /* Number of undefines */
static char *UserInc[MAXINCDIRS]; /* Table of include dirs */
static int NUserInc = 0; /* Number of include dirs */
static char *Libs[MAXLIBS]; /* Table of library args */
static int NLibs = 0; /* Number of library args */
/*
* The command line buffer for child commands is allocated statically,
* rather than as an automatic, to forstall problems with stack limits
* in initial implementations. Hopefully, automatic stack growth will
* be implemented in future release of the C compiler. If nothing
* else, someday I will read the manuals and figure out how to explicitly
* grow the stack...
*
*/
static char Command[CMDBUFFERSIZE]; /* Command line buffer */
static char *EndCommand = Command; /* End of current command */
/*
* Macros to determine the suffix type of a file given a pointer to
* its operand structure.
*/
#define CFILE(op) (strcmp(op->Suffix,"c")==0)
#define SFILE(op) (strcmp(op->Suffix,"s")==0)
#define OFILE(op) (strcmp(op->Suffix,"o")==0)
/*
* Now some macros to enable abort on control-C.
*/
# define CHECKABORT
/*
* Set list of places to search for various executables, libraries, etc.
* Searched in order, first match wins, null string is current directory.
* Note that these names are used as prefixes exactly as given, so
* device names must end in ':' and directory names must end in '/'.
*
*/
static char *BinDirs[] = {
"",
"LC:",
NULL
};
static char *LibDirs[] = {
"",
"LIB:",
NULL
};
/*
* Flags set by command line arguments/
*/
static int cflag; /* -c flag given */
static int Pflag; /* -P flag given */
static int Sflag; /* -S flag given */
static int gflag; /* -g flag given */
static int Vflag; /* -V flag given (non-standard) */
/* Amiga specific flags */
static int scflag; /* -Ac flag given */
static int sdflag; /* -Ad flag given */
static int FFPflag; /* -Af flag given */
static int protoflag; /* -Ap flag given */
static int shortflag; /* -As flag given */
static int Avflag; /* -Av flag given */
static int Ayflag; /* -Ay flag given */
static int ACflag; /* -AC flag given */
static int ADflag; /* -AD flag given */
static int ABflag; /* -AB flag given */
static int sourceflag; /* -AS flag given */
static int ErrCount = 0; /* Count of compile/assemble errors */
static char *outfile = "a.out"; /* Output file name from linker */
static char *QuadDev = QUADDEV; /* Where to keep quad files */
static char *Locate (char *, char **); /* Find a file */
static void AddToCommand (char *, ); /* Add argument to command buffer */
static void InitCommand (void); /* Initialize command buffer */
static void Fatal (char *, ); /* Quit with fatal error */
static void Warning (char *, ); /* Issue warning message */
static void AddOperandToList (char *); /* Add .c, .s, or .o file to list */
static void CleanObjects (void); /* Remove .o for link and go mode */
static void MakeObjects (void); /* Reduce to list of object files */
static void ParseCommandLine (int, char **);
/* Deal with command line */
static void Compile (struct Operand *); /* Translate from .c to .o */
static void Assemble (struct Operand *);/* Translate from .s to .o */
static void Link (void); /* Gather .o's into executable */
static int Pass1 (struct Operand *); /* Pass 1 of the compiler */
static int Pass2 (struct Operand *); /* Pass 2 of the compiler */
static int RunCommand (void); /* Run a command */
static int Readable (char *); /* Check to see if a file is readable */
extern void exit (int); /* See exit(2) */
extern int system (char *); /* See system(2) */
/*
* Main entry point. Note that despite common usage where main is
* essentially of type void, we declare it explicitly to return
* an int, and actually return a value. In most implementations,
* the value returned from main is the exit status of the program.
* Whether this applies to Lattice C or not, I'm not sure yet.
*/
int main (argc, argv)
int argc;
char **argv;
{
DBUG_ENTER ("main");
ParseCommandLine (argc, argv);
MakeObjects ();
if (!cflag && !Pflag && !Sflag && ErrCount == 0) {
Link ();
CleanObjects ();
}
DBUG_RETURN (0);
}
/*
* The following macro is used to allow optional whitespace between
* an option and it's argument. Argp is left pointing at the option
* and argv and argc are adjusted accordingly if necessary.
*
* Note that there is no check for missing option arguments. In
* particular, -o -V will blindly take -V as the output file name.
*
*/
#define XARG(argc,argv,argp) {if(*++argp==EOS){argp=(*argv++);argc--;}}
static void
ParseCommandLine (argc, argv) int argc; char **argv;
{
register char *argp;
DBUG_ENTER ("ParseCommandLine");
argc--;
argv++;
while (argc-- > 0) {
argp = *argv++;
if (*argp != '-') {
AddOperandToList (argp);
} else {
switch (*++argp) {
case '#': /* For DBUG, I assume - mwm */
XARG (argc, argv, argp);
DBUG_PUSH (argp);
break;
case 'A': /* Amiga flags, non-standard */
while (*++argp) {
switch (*argp) {
case 'C': /* Place code in chip ram */
ACflag++;
break;
case 'D': /* Place data in chip ram */
ADflag++;
break;
case 'B': /* Place BSS in chip ram */
ABflag++;
break;
case 'S': /* Turn source listing back on */
sourceflag++ ;
break ;
case 'c': /* Generate smallcode model */
scflag++;
break;
case 'd': /* Generate smalldata model */
sdflag++;
break;
case 'f': /* Use the Motorola FFP instead of IEEE */
FFPflag++ ;
break ;
case 'p': /* Turn off prototype checking */
protoflag++ ;
break ;
case 'q': /* Specify where quad file goes */
XARG (argc, argv, argp);
QuadDev = argp;
goto NoMoreAmiga;
case 's': /* Short integers! */
shortflag++ ;
break;
case 'v': /* Disable stack checking */
Avflag++;
break;
case 'y': /* Load A6 with LinkerDB */
Ayflag++ ;
break ;
}
}
NoMoreAmiga: break; /* Out of Amiga loop. Need multi-level break! */
case 'B': /* Use backup compiler, possibly as specified */
break; /* NOP for now */
case 'C': /* Have cpp not elide comments */
break; /* NOP for now */
case 'c': /* Produce .o file, don't load */
cflag++;
break;
case 'D': /* Define value for cpp */
XARG (argc, argv, argp);
if (NDefines >= MAXDEFINES) {
Fatal ("too many -D args (%d max)", MAXDEFINES);
}
Defines[NDefines++] = argp;
break;
case 'E': /* Only run preprocessor, result to stdout */
Pflag++;
break;
case 'f': /* Don't force auto-convert float to double */
break; /* NOP for now, just eat it */
case 'g': /* Produce debugging output */
gflag++;
break;
case 'I': /* Add directory for include file searches */
XARG (argc, argv, argp);
if (NUserInc >= MAXINCDIRS) {
Fatal ("too many -I args (%d max)", MAXINCDIRS);
}
UserInc[NUserInc++] = argp;
break;
case 'L': /* Search for libraries in specified dir */
break; /* NOP for now */
case 'l': /* another library to use at link time */
XARG (argc, argv, argp);
if (NLibs > MAXLIBS) {
Fatal ("too many -l args (%d max)", MAXLIBS);
}
Libs[NLibs++] = argp;
break;
case 'M': /* Generate Makefile dependencies */
break; /* NOP for now */
case 'O': /* enable the optimizer */
break; /* NOP for now, just eat it */
case 'o': /* Name of output file */
XARG (argc, argv, argp);
outfile = argp;
break;
case 'p': /* turn on the profiler */
break; /* NOP for now */
case 'P': /* Same as -E, for sysV compatability */
Pflag++;
break;
case 'R': /* make initialized variables read-only */
break; /* NOP for now */
case 'S': /* Produce assmebler output */
Sflag++;
Warning ("-S option not yet implemented, ignored");
break;
case 's': /* Some system V thingy, I suppose */
break; /* NOP for now, just eat it */
case 't': /* Specify which passes to use from -B */
break; /* NOP for now */
case 'U': /* Undefine the rest of the argument */
XARG (argc, argv, argp);
if (NUnDefines >= MAXUNDEFINES) {
Fatal ("too many -U args (%d max)", MAXUNDEFINES);
}
UnDefines[NUnDefines++] = argp;
break;
case 'V': /* Verbose mode, dump actual commands */
Vflag++;
break;
case 'w': /* Turn off warnG_ENTER ("MakeObjects");
for (index = 0; index < NOperands; index++) {
CHECKABORT;
op = &Operands[index];
if (NOperands > 1 && (CFILE (op) || SFILE (op))) {
printf ("%s.%s:\n", op -> Rootname, op -> Suffix);
}
if (CFILE (op)) {
Compile (op);
} else if (SFILE (op)) {
Assemble (op);
}
}
DBUG_VOID_RETURN;
}
/*
* Note that commands to cc of the form d)
{
register int index;
register struct Operand *op;
register char *name;
auto char buffer[ARGSIZE];
DBUG_ENTER ("Link");
CHECKABORT;
InitCommand ();
AddToCommand ("%s ", Locate ("blink", BinDirs)); /* 3.10 uses blink - mwm*/
/* Change Lstartup.obj to c.o for 3.03 -- mwm */
AddToCommand ("%s", Locate ("c.o", LibDirs));
for (index = 0; index < NOperands; index++) {
op = &Operands[index];
if (OFILE (op)) {
name = op -> Rootname;
} else {
name = op -> Basename;
}
AddToCommand ("+%s.o", name);
}
AddToCommand ("%s", " library ");
for (index = 0; index < NLibs; index++) {
sprintf (buffer, "%s.lib", Libs[index]);
AddToCommand ("%s+", Locate (buffer, LibDirs));
}
if (FFPflag) AddToCommand("%s+", Locate ("lcmffp.lib", LibDirs));
AddToCommand ("%s+", Locate ("lc.lib", LibDirs));
AddToCommand ("%s", Locate ("amiga.lib", LibDirs));
if (scflag) AddToCommand (" %s", "SC");
if (sdflag) AddToCommand (" %s", "SD");
if (gflag) AddToCommand (" %s", "ADDSYM");
AddToCommand (" %s", "ND BATCH");
AddToCommand (" to %s map nil:", outfile);
(void) RunCommand ();
DBUG_VOID_RETURN;
}
/*VARARGS1*/
static void
Warning (fmt, arg1, arg2, arg3)
char *fmt, *arg1, *arg2, *arg3;
{
fprintf (stderr, "cc -- warning: ");
fprintf (stderr, fmt, arg1, arg2, arg3);
fprintf (stderr, "\n");
(void) fflush (stderr);
}
/*VARARGS1*/
static void
Fatal (fmt, arg1, arg2, arg3)
char *fmt, *arg1, *arg2, *arg3;
{
fprintf (stderr, "cc -- fatal error: ");
fprintf (stderr, fmt, arg1, arg2, arg3);
fprintf (stderr, "\n");
(void) fflush (stderr);
exit (1);
}
/*
* Split an operand name into rootname, basename, and suffix
* components. The rootname is the full name, minus any suffix,
* but including any prefix. The basename is the rootname minus
* any prefix. The suffix is anything after the last '.' character.
* Only the suffix is allowed to be the null string.
*/
static void
AddOperandToList (filename) char *filename;
{
register char *split;
register struct Operand *op;
extern char *strrchr ();
DBUG_ENTER ("AddOperandToList");
DBUG_3 ("ops", "add file '%s' to operand list", filename);
if (NOperands >= MAXOPERANDS) {
Fatal ("too many files (%d max)\n", MAXOPERANDS);
}
op = &Operands[NOperands];
op -> Rootname = filename;
if ((split = strrchr (filename, '/')) == NULL) {
split = strrchr (filename, ':');
}
if (split == NULL) {
op -> Basename = filename;
} else {
op -> Basename = ++split;
}
if ((split = strrchr (filename, '.')) == NULL) {
op -> Suffix = "";
} else {
*split++ = EOS;
op -> Suffix = split;
}
DBUG_3 ("ops", "rootname '%s'", op -> Rootname);
DBUG_3 ("ops", "basename '%s'", op -> Basename);
DBUG_3 ("ops", "suffix '%s'", op -> Suffix);
NOperands++;
DBUG_VOID_RETURN;
}
/*
* Compile one operand from a C source program to an object module.
*/
static void
Compile (op) struct Operand *op;
{
DBUG_ENTER ("Compile");
CHECKABORT;
if (!Sflag && !Pass1 (op) && !Pflag) { /* Order important! */
CHECKABORT;
(void) Pass2 (op);
}
DBUG_VOID_RETURN;
}
/*
* Note that because of brain-damage in the fact that -p to lc1 removes
* all predefined defs, we must add them so replacing -c with -P in the
* cc command line will result in the same set of predefined symbols.
* This is rather ugly and leaves a hole for future problems if we
* get out of sync with respect to what names the compiler predefines.
*/
static int
Pass1 (op) register struct Operand *op;
{
register int status;
register int index;
DBUG_ENTER ("Pass1");
CHECKABORT;
InitCommand ();
AddToCommand ("%s", Locate ("lc1", BinDirs));
if (Pflag) {
AddToCommand (" -o%s.i -p -DAMIGA -DM68000 -DSPTR -DLATTICE", op -> Basename);
} else {
AddToCommand (" -o%s%s.q", QuadDev, op -> Basename);
}
for (index = 0; index <NUserInc; index++) {
AddToCommand (" -i%s/", UserInc[index]);
}
for (index = 0; index <NUnDefines; index++) {
AddToCommand (" -u%s", UnDefines[index]);
/*************************
Warning ("-U%s ignored! (unimplemented)", UnDefines[index]);
**************************/
}
AddToCommand(" -d%s", "LATTICE"); /* Make sure LATTICE is defined */
for (index = 0; index <NDefines; index++) {
AddToCommand (" -d%s", Defines[index]);
}
if (!sdflag) AddToCommand (" -%s", "b0"); /* Small code */
if (gflag) AddToCommand (" -%c", 'd'); /* Debug */
if (!protoflag) AddToCommand(" -c%c", 'f'); /* no missing proto warnings */
if (!sourceflag) AddToCommand(" -c%c", 'e');/* turn on source listings */
if (FFPflag) AddToCommand(" -%c", 'f'); /* FFP floating point */
if (shortflag) AddToCommand(" -%c", 'w'); /* Short integers */
/* Turn off output noise, turn on more checking */
AddToCommand (" %s", "-ct -c+ -.") ;
AddToCommand (" %s", op -> Rootname);
status = RunCommand ();
DBUG_RETURN (status);
}
/*
* Run second pass of compiler on a single operand.
*/
static int
Pass2 (op) struct Operand *op;
{
int status;
DBUG_ENTER ("Pass2");
CHECKABORT;
InitCommand ();
AddToCommand ("%s", Locate ("lc2", BinDirs));
AddToCommand (" -. -o%s.o", op -> Basename);
if (!scflag) AddToCommand (" -%s", "r0");
if (Avflag) AddToCommand (" -%c", 'v');
if (ABflag || ACflag || ADflag)
AddToCommand (" -c%s%s%s", /* Ugly, but... */
ABflag ? "b" : "",
ACflag ? "c" : "",
ADflag ? "d" : "") ;
if (Ayflag) AddToCommand(" -%c", 'y'); /* Load A6 for the user */
AddToCommand (" %s%s", QuadDev, op -> Basename);
status = RunCommand ();
DBUG_RETURN (status);
}
/*
* I have not yet had occasion to use the macro assembler, so this
* part is not yet implemented. If anyone wants to send me the
* appropriate code, I will be glad to install it.
*/
static void
Assemble (op) struct Operand *op;
{
DBUG_ENTER ("Assemble");
CHECKABORT;
Warning ("assembly pass not yet implemented");
ErrCount++;
DBUG_VOID_RETURN;
}
/*
* As far as I can tell, the child status is not returned, only
* whether or not the child could be run. So, how do we find out
* whether there was an error or not? It's probably in the manuals
* somewhere, I just haven't had time to dig yet.
*
* Note that because Lattice printf is not capable of printing more
* than 200 characters at a time, we must spit them out one at a time
* to make sure the entire command line gets printed when -V is used.
*
*/
static int
RunCommand (void)
{
int status;
register char *cmdp;
DBUG_ENTER ("RunCommand");
DBUG_3 ("cmd", "execute '%s'", Command);
if (Vflag) {
for (cmdp = Command; *cmdp != '\000'; cmdp++) {
putchar (*cmdp); /* see above */
}
putchar ('\n');
(void) fflush (stdout);
}
status = system (Command);
DBUG_3 ("sys", "subcommand returns status %d", status);
if (status) {
ErrCount++;
}
DBUG_RETURN (status);
}
/*
* Look through the list of paths pointed to by "vec" until we find
* a file with name given pointed to by "namep". If none is found,
* the name pointed to by namep is returned.
*/
static char *
Locate (namep, vec)
char *namep, **vec;
{
static char namebuf[ARGSIZE];
DBUG_ENTER ("Locate");
while (*vec != NULL) {
(void) sprintf (namebuf, "%s%s", *vec, namep);
DBUG_3 ("try", "look for '%s'", namebuf);
if (Readable (namebuf)) {
namep = namebuf;
break;
}
vec++;
}
DBUG_RETURN (namep);
}
/*
* Check to see if the file exists and is readable.
*/
#include <libraries/dos.h>
static int
Readable (name) char *name;
{
register int status = 0;
register int fildes;
DBUG_ENTER ("Readable");
#ifdef unix
fildes = open (name, O_RDONLY);
if (fildes >= 0) {
(void) close (fildes);
status = 1;
}
#else
fildes = Lock (name, ACCESS_READ);
if (fildes != 0) {
UnLock (fildes);
status = 1;
}
#endif
DBUG_RETURN (status);
}
/*
* Initialize the command line buffer and associated variables to
* discard any previous command line.
*/
static void
InitCommand (void)
{
Command[0] = '\000';
EndCommand = Command;
}
/*
* Build string to add to end of current command line, checking
* for overflow in the command buffer and maintaining the pointer
* to the end of the current command.
*
* Note that we are a "printf type" of command, and can be called
* with up to three "char *" arguments. There is a portability
* problem here, but Lattice hasn't yet made "varargs" a standard
* part of their distribution.
*
* Also, note that the return argument of sprintf is supposed to be
* the number of characters to be added to the buffer. This is
* not always true for some C implementations. In particular,
* sprintf in BSD4.1 returns a pointer. Thus we don't use the
* return argument.
*
*/
/*VARARGS1*/
static void
AddToCommand (fmt, arg1, arg2, arg3)
char *fmt;
char *arg1, *arg2, *arg3;
{
register int length;
auto char buffer[ARGSIZE];
(void) sprintf (buffer, fmt, arg1, arg2, arg3);
length = strlen (buffer);
if ((EndCommand - Command) + length >= sizeof (Command)) {
Fatal ("command line too long (%d char max)", sizeof (Command));
} else {
(void) strcat (EndCommand, buffer);
EndCommand += length;
}
}
/*
* If an executable is made from a single C file, the normal behavior
* for the unix environment is to treat the .o file as an intermediate
* file and remove it, so we follow suit.
*/
static void
CleanObjects (void)
{
auto char buffer[ARGSIZE];
register struct Operand *op;
DBUG_ENTER ("CleanObjects");
if (NOperands == 1) {
op = &Operands[0];
if (CFILE (op) || SFILE (op)) {
sprintf (buffer, "%s.o", op -> Basename);
if (!DeleteFile (buffer)) {
Warning ("can't delete '%s'", buffer);
}
}
}
DBUG_VOID_RETURN;